﻿$Global:Loggers=$null

function Out-ToLogXmlFormat
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [String] 
        $Path,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Object] 
        $Server,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [String] 
        $ComponentName,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Object] 
        $InputObject
        )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Out-ToLogXmlFormat in  $Path"
    }
    End
    {
        write-verbose "End Out-ToLogXmlFormat in  $Path"
        $watch.Stop();
        Write-Verbose "Out-ToLogXmlFormat : $($watch.Elapsed)"
    }
    Process
    {
        $doc = Get-XmlLogOutput -Path $Path
        $serverNode = Set-ServerXmlNode -Document $doc -ParentNode $doc.DocumentElement -ElementName "Server" -Server $Server

        $componentNode = $serverNode.SelectSingleNode("//Server[@Name='$($Server.Name)']/Components[@Name='$($ComponentName)']")

        if ($componentNode -eq $null)
        {
            Set-XmlNode -Document $doc -ParentNode $serverNode -ElementName "DeploymentActions" -InputObject $InputObject  | Out-Null
        }
        else
        {
            Set-XmlNode -Document $doc -ParentNode $componentNode -ElementName "DeploymentActions" -InputObject $InputObject  | Out-Null            
        }

        $doc.Save($Path)
    }
}

Function Set-ServerXmlNode
{
   Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Xml.XmlDocument] 
        $Document,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Xml.XmlElement] 
        $ParentNode,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [String] 
        $ElementName,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Object] 
        $Server

        )
     Process
    {
        $serverNode = $ParentNode.SelectSingleNode("//Server[@Name='$($Server.Name)']")
        if ($serverNode -eq $null)
        {
            Set-XmlNode -Document $doc -ParentNode $ParentNode -ElementName "Server" -InputObject $Server | Out-Null            
        }

        $serverNode = $ParentNode.SelectSingleNode("//Server[@Name='$($Server.Name)']")
        Write-Output $serverNode

    }
}

Function Set-XmlNode
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Xml.XmlDocument] 
        $Document,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Xml.XmlElement] 
        $ParentNode,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [String] 
        $ElementName,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [System.Object] 
        $InputObject

        )
    Process
    {
        
        $newNode = $Document.CreateElement($ElementName)
        $ParentNode.AppendChild($newNode)

        $InputObject | Get-Member -MemberType NoteProperty, Property | ForEach-Object{
            if ($_.Definition.StartsWith("System.Object[]") -or $_.Definition.StartsWith("Deserialized.System.Object[]"))
            {
                Write-verbose "Add collectionas child nodes for property $($_.Name) with type $($_.Definition)"

                $collectionElements = $InputObject.$($_.Name)
                foreach($element in $collectionElements)
                {
                    
                    try
                    {
                        $elementType=$element.GetType().Name    
                    }
                    catch
                    {}
                
                
                    if ($elementType -eq "String")
                    {
                        $attributeValue = $element

                        $newNodeLineResult = $Document.CreateElement("detailedResultLine")
                        $newNode.AppendChild($newNodeLineResult)
                        $newNodeLineResult.InnerText = $attributeValue
                        
                        write-verbose "Add attribute $($_.Name) with type String and value of $attributeValue"
                        if (($attributeValue -eq $null) -or ([System.String]::IsNullorEmpty($attributeValue)))
                        {
                            $attributeValue = ""
                        }
                        $newNode.SetAttribute($($_.Name),$attributeValue)
                    }
                    else
                    {
                        Set-XmlNode -Document $Document -ParentNode $newNode -ElementName $_.Name -InputObject $element | Out-Null
                    }    
                }
            }
            else
            {
                if ($_.Definition.StartsWith("System.Object") -or $_.Definition.StartsWith("Deserialized."))
                {
                    Write-verbose "Expand object for property $($_.Name) with type $($_.Definition)"
                    Set-XmlNode -Document $Document -ParentNode $newNode -ElementName $_.Name -InputObject $InputObject.$($_.Name) | Out-Null
                }
                else
                {
                    $attributeValue = $InputObject.$($_.Name)
                    write-verbose "Add attribute $($_.Name) with type $($_.Definition) and value of $attributeValue"
                    if (($attributeValue -eq $null) -or ([System.String]::IsNullorEmpty($attributeValue)))
                    {
                        $attributeValue = ""
                    }

                    $newNode.SetAttribute($($_.Name),$attributeValue)
                }
            }
            

        }
        Write-Output $newNode

    }


}



Function Get-XmlLogOutput
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [String] 
        $Path
    )
     Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Get-XmlLogOutput in  $Path"
    }
    End
    {
        write-verbose "End Get-XmlLogOutput in  $Path"
        $watch.Stop();
        Write-Verbose "Get-XmlLogOutput : $($watch.Elapsed)"
    }
    Process
    {
        
        #new xml log file if it doesnt exist
        new-XmlLogFile -Path $Path | Out-Null

        #read the file log
        $doc = New-Object System.Xml.XmlDocument
        $doc.Load($Path)

        Write-Output $doc
   
    }
}

function new-XmlLogFile
{
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [String] 
        $Path
    )
    Process
    {
        if(!(Test-Path $Path))
        {
            $doc = New-Object System.Xml.XmlDocument

            $description = $doc.CreateXmlDeclaration("1.0",$null,$null)
            $doc.AppendChild($description)

            $root = $doc.CreateElement("deploymentState")
            $doc.AppendChild($root)
            $doc.Save($Path)
        }
    }
}

Function Get-TransformedLog
{
        [cmdletbinding()]
        Param( 
        [Parameter(Mandatory=$true)] 
        [String] 
        $ApplicationName,

        [Parameter(Mandatory=$true)] 
        [String] 
        $ApplicationVersion,

        [Parameter(Mandatory=$true)] 
        [DateTime] 
        $Start,
        
        [Parameter(Mandatory=$true)] 
        [DateTime] 
        $End,
        
        [Parameter(Mandatory=$false)] 
        [String] 
        $ActionsTitle = "Management actions"
                        
        )
 
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Get-TransformedLog from $($Configuration.Logger.Logfile) for Application $ApplicationName"
    }
    End
    {
        write-verbose "End Get-TransformedLog from $($Configuration.Logger.Logfile) for Application $ApplicationName"
        $watch.Stop();
        Write-Verbose "Get-TransformedLog duration : $($watch.Elapsed)"
    }
    Process 
    {
    
        try
        {
            if ((Test-Path $Configuration.Logger.Logfile -PathType Leaf) -ne $true)
            {
                Write-Warning "log file $($Configuration.Logger.Logfile) doesn't exist"
                Write-Output "Empty log : $($Configuration.Logger.Logfile)"
            }
            

            #Get the module path
            $moduleItem = (Get-ApplicationManagementModulePath | Get-Item)
            $xsltFilePath = $moduleItem.Directory.FullName
            $xsltFilePath = Join-Path -Path $xsltFilePath -ChildPath "Log4EndUser.xslt"

            if ((Test-Path $xsltFilePath -PathType Leaf) -ne $true)
            {
                Write-Warning "xslt file $xsltFilePath doesn't exist"
                Get-Content -Path $Configuration.Logger.Logfile
                return                 
            }

            
            [System.Xml.Xsl.XsltArgumentList] $argsList = New-Object System.Xml.Xsl.XsltArgumentList;
            $argsList.AddParam("application", "", $ApplicationName);
            $argsList.AddParam("version", "", $ApplicationVersion);
            $argsList.AddParam("startTime", "", $Start);
            $argsList.AddParam("endTime", "", $End);
            $argsList.AddParam("duration", "", $(($End - $Start).ToString()));
            $argsList.AddParam("actionsTitle", "", $ActionsTitle);

            [System.Xml.Xsl.XslCompiledTransform] $transform = New-Object System.Xml.Xsl.XslCompiledTransform -ArgumentList $true;
            $transform.Load($xsltFilePath);
                
                
            [System.IO.MemoryStream] $ms = New-Object System.IO.MemoryStream
            [System.IO.StreamWriter] $sw = New-Object System.IO.StreamWriter -ArgumentList $ms
            $transform.Transform($($Configuration.Logger.Logfile), $argsList, $sw)
            $sw.Flush()

            $ms.Position = 0
            [System.IO.StreamReader] $sr = New-Object System.IO.StreamReader -ArgumentList $ms
            Write-Output $sr.ReadToEnd()


            
        }
        finally
        {
            if ($ms -ne $null)
            {
                $ms.close()
                $ms.Dispose()
            }
        }            
    }
}


